/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "rtc.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>

#include "bmp280.h"
#include "aht20.h"
#include "IR.h"
#include "command.h"
#include "W25Qxx.h"

#include "buzzer.h"
#include "hlw8012.h"

#include "my_task_os.h"
#include "ws2812.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define SENSOR_ID 0x01  //此设备地址

//指令
#define Read_sensor_data 0x12  //网关读取传感器指令
#define Driver_reboot 0x13     //设备重启
#define driver_update_data 0x14 //设备上报数据

#define CMD_TURN_ON_LIGHT 0x55 //开灯指令 U
#define CMD_TURN_OFF_LIGHT 0x56 //开灯指令
#define CMD_TURN_ON_AIRCON 0x57 //打开空调
#define CMD_TURN_OFF_AIRCON 0x58 //关闭空调
#define CMD_AUTO_MODE 0x59 //自动模式
#define CMD_MANUAL_MODE 0x60 //手动模式
#define CMD_TURN_OFF_ALL_LIGHT 0x61 //关闭所有灯光
#define CMD_TURN_OFF_ALL_AIRCON 0x62 //关闭所有空调
#define CMD_OFF_POWER 0x63 //一键断电
#define CMD_ON_AUTO_MODE 0x64 //一键自动

#define CMD_TURN_ON_LIGHT_1  0x65//打开灯光1
#define CMD_TURN_ON_LIGHT_2  0x66//打开灯光2
#define CMD_TURN_ON_LIGHT_3  0x67//打开灯光3
#define CMD_TURN_ON_LIGHT_4  0x68//打开灯光4
#define CMD_TURN_OF_LIGHT_1  0x69//关闭灯光1
#define CMD_TURN_OF_LIGHT_2  0x6A//关闭灯光2
#define CMD_TURN_OF_LIGHT_3  0x6B//关闭灯光3
#define CMD_TURN_OF_LIGHT_4  0x6C//关闭灯光4


//串口缓冲
uint8_t readBuffer[64];

uint8_t command[50];
int commandLength = 0;

//FLASH
uint8_t wData[0x100];   //写缓存数组
uint8_t rData[0x100];   //读缓存数组
uint8_t ID[4];          //设备ID缓存数组
uint32_t i;

//Lora忙状态
#define LORA_STA HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)

//火焰检测引脚
#define Fire_check HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)

//检测是否有人
#define IF_SOMBODY_STA HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11)
//测试继电器流水灯
uint8_t counter = 0; // 计数器（0~31，因为 5 位二进制最大值为 31）


//发送传感器数据结构体
#pragma pack(push, 1) // 确保单字节对齐
typedef struct {
  float    AHT20_temperature; //4字节
  float    AHT20_humidity;
  float    BMP280_temperature;
  float    BMP280_pressure;
  float    light;
  float    power;
  float    voltage;
  float    current;
  float    energy;
  uint32_t  nowstatus;//0-4为灯状态 5为是否有人 6为模式 7为火焰
  uint32_t timestamp;
} SensorData;
#pragma pack(pop)

// 定义解析结果状态码
typedef enum {
  PARSE_OK = 0,
  PARSE_CHECKSUM_ERROR,
  PARSE_LENGTH_MISMATCH
} ParseStatus;

//电能计量
float hlw_current = 0;
float hlw_power = 0;
float hlw_voltage = 0;

//变量
float voltage = 0.0f;
uint32_t time_count = 0;


uint8_t data_buffer[44];

//电能
HLW8012_Data hlw_data;
SensorData sensor;

BMP280_HandleTypedef bmp280_dev;
AHT20_Data aht_data;
float BMP280_pressure, BMP280_temperature;

//模式
#define AUTO_MODE 1
#define MANUAL_MODE 0
uint8_t driver_mode = AUTO_MODE;

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void test_flash()
{
  printf("\r\n SPI-W25Qxx Example \r\n\r\n");

  /*-Step1- 验证设备ID  ************************************************Step1*/
  BSP_W25Qx_Init();
  BSP_W25Qx_Read_ID(ID);
  //第一位厂商ID固定0xEF,第二位设备ID根据容量不同,具体为：
  //W25Q16为0x14、32为0x15、40为0x12、64为0x16、80为0x13、128为0x17
  //单位为Mbit,32/8 = 4MB = 4,194,304Byte
  if((ID[0] != 0xEF) | (ID[1] != 0x15)) {
    printf("ID is wrong!!\r\n");
  } else {
    printf(" W25Qxx ID is : ");
    for(i=0; i<2; i++) {
      printf("0x%02X ",ID[i]);
    }
    printf("\r\n");
  }
  /*-Step2- 擦除块  ************************************************Step2*/
  if(BSP_W25Qx_Erase_Block(0) == W25Qx_OK)
    printf(" QSPI Erase Block OK!\r\n");
  else
    printf("something wrong in Step2\r\n");
  /*-Step3- 写数据  ************************************************Step3*/
  for(i =0; i<0x100; i ++) {
    wData[i] = i;
    rData[i] = 0;
  }

  if(BSP_W25Qx_Write(wData,0x00,0x100)== W25Qx_OK)
    printf(" QSPI Write OK!\r\n");
  else
    printf("something wrong in Step3\r\n");
  /*-Step4- 读数据  ************************************************Step4*/
  if(BSP_W25Qx_Read(rData,0x00,0x100)== W25Qx_OK)
    printf(" QSPI Read ok\r\n\r\n");
  else
    printf("something wrong in Step4\r\n");

  printf("QSPI Read Data : \r\n");
  for(i =0; i<0x100; i++)
    printf("0x%02X  ",rData[i]);
  printf("\r\n\r\n");
  /*-Step5- 数据对比  ************************************************Step5*/
  if(memcmp(wData,rData,0x100) == 0 )
    printf(" W25Q64FV QuadSPI Test OK\r\n");
  else
    printf(" W25Q64FV QuadSPI Test False\r\n");
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  if (huart == &huart1) {
    Command_Write(readBuffer, Size);
    HAL_UARTEx_ReceiveToIdle_IT(&huart1, readBuffer, sizeof(readBuffer));
  }
}


/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/**
 * 将1位数据设置到32位数据的指定位置
 * @param original 原始32位数据
 * @param bit 要设置的位值(0或1)
 * @param position 要设置的位置(0-31)
 * @return 设置后的32位数据
 */
uint32_t setBitInUint32(uint32_t original, uint8_t bit, uint8_t position) {
    // 确保bit是0或1
    bit = bit & 0x01;
    
    // 创建掩码，清除目标位置的位
    uint32_t mask = ~(1U << position);
    
    // 清除目标位置的位，然后设置新值
    return (original & mask) | ((uint32_t)bit << position);
}

//关闭所有继电器
void turn_off_all_switch(void)
{
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
}

//打开所有继电器
void turn_on_all_switch(void)
{
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
}

//打开灯
void trun_on_light(void)
{
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
}

//关闭灯
void trun_off_light(void)
{
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);
}

//开关灯 传入指令
void trun_on_off_light(uint8_t cmd)
{
  switch(cmd) {
  case CMD_TURN_ON_LIGHT_1:
    //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
    break;
  case CMD_TURN_ON_LIGHT_2:
    //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
    break;
  case CMD_TURN_ON_LIGHT_3:
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
    break;
  case CMD_TURN_ON_LIGHT_4:
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
    break;
  case CMD_TURN_OF_LIGHT_1:
    //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);
    break;
  case CMD_TURN_OF_LIGHT_2:
    //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
    break;
  case CMD_TURN_OF_LIGHT_3:
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);
    break;
  case CMD_TURN_OF_LIGHT_4:
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
    break;
  default:
    // 默认
    break;
  }
}

//测试继电器
void test_jidianqi()
{
  // 将 counter 的二进制值写入 PB11~PB15
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, (counter & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, (counter & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, (counter & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, (counter & 0x08) ? GPIO_PIN_SET : GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, (counter & 0x10) ? GPIO_PIN_SET : GPIO_PIN_RESET);

  counter++; // 计数器加 1
  if (counter > 31) counter = 0; // 溢出归零（5 位二进制最大 31）
}

void pack_sensor_data(uint8_t *buffer, SensorData *data)
{
  memcpy(buffer, data, sizeof(SensorData));
}

//解析数据任务
void analysisData_TASK(void)
{
  commandLength = Command_GetCommand(command);
  if (commandLength != 0) {
    switch(command[3]) {
    case CMD_TURN_ON_LIGHT_1:
    case CMD_TURN_ON_LIGHT_2:
    case CMD_TURN_ON_LIGHT_3:
    case CMD_TURN_ON_LIGHT_4:
    case CMD_TURN_OF_LIGHT_1:
    case CMD_TURN_OF_LIGHT_2:
    case CMD_TURN_OF_LIGHT_3:
    case CMD_TURN_OF_LIGHT_4:
      // Handle all light control commands with the unified function
      trun_on_off_light(command[3]);
      driver_mode = MANUAL_MODE;  //切为手动模式
      break;
    case CMD_TURN_ON_LIGHT:
      // 处理开灯指令
      trun_on_light();
      break;
    case CMD_TURN_OFF_LIGHT:
      // 处理关灯指令
      trun_off_light();
      break;
    case CMD_TURN_ON_AIRCON:
      // 处理打开空调指令
      break;
    case CMD_TURN_OFF_AIRCON:
      // 处理关闭空调指令
      break;
    case CMD_AUTO_MODE:
      // 处理自动模式指令
      break;
    case CMD_MANUAL_MODE:
      // 处理手动模式指令
      break;
    case CMD_TURN_OFF_ALL_LIGHT:
      // 处理关闭所有灯光指令
      turn_off_all_switch();
      break;
    case CMD_TURN_OFF_ALL_AIRCON:
      // 处理关闭所有空调指令
      break;
    case CMD_OFF_POWER:
      // 处理一键断电指令
      break;
    case CMD_ON_AUTO_MODE:
      // 处理一键自动指令
      break;
    case 0x03:
      // 处理更新传感器命令
      pack_sensor_data(data_buffer, &sensor);
      send_data_frame(&huart1, data_buffer, sizeof(data_buffer));
      break;
    default:
      // 处理未知指令
      break;
    }
  }
}

//传感器数据更新任务
void read_sensor_TASK(void)
{
  //读取光照强度
  HAL_ADC_Start(&hadc1);
  // 等待转换完成（超时 10ms）
  if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) {
    uint32_t adc_value = HAL_ADC_GetValue(&hadc1); // 读取原始值（0~4095）
    voltage = adc_value * 3.3f / 4095;    // 转换为电压（0~3.3V）
  }
  HAL_ADC_Stop(&hadc1);

  //读取气压
  bmp280_read_float(&bmp280_dev, &BMP280_temperature, &BMP280_pressure, NULL);

  //读取温湿度
  AHT20_ReadData(&aht_data);
}

//蜂鸣器tick任务
void buzzer_tick_TASK(void)
{
  Buzzer_Update10ms();
}

//获取电能任务
void get_hlw_data_TASK(void)
{
  //hlw_data = get_hlw_data();
  hlw_data.power = HLW8012_GetPower();
  hlw_data.current = HLW8012_GetCurrent();
  hlw_data.voltage = HLW8012_GetVoltage();
  hlw_data.energy = HLW8012_GetEnergy();

}

//nowstatus 格式说明
//0-4为灯状态
//第5位为有人状态 0-无人 1-有人
//第6位为模式状态 0-手动 1-自动
//第7位为火焰状态 0-无火焰 1-有火焰

//数据打包任务
void pack_data_TASK(void)
{
  //nowstatus 设置
  uint32_t nowstatus = 0;
  nowstatus = setBitInUint32(nowstatus, HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11), 0); // 灯1
  nowstatus = setBitInUint32(nowstatus, HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12), 1); // 灯2
  nowstatus = setBitInUint32(nowstatus, HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13), 2); // 灯3
  nowstatus = setBitInUint32(nowstatus, HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14), 3); // 灯4
  nowstatus = setBitInUint32(nowstatus, HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15), 4); // 灯5
  nowstatus = setBitInUint32(nowstatus, IF_SOMBODY_STA, 5); // 有人状态
  nowstatus = setBitInUint32(nowstatus, driver_mode, 6); // 模式
  nowstatus = setBitInUint32(nowstatus, Fire_check, 7); // 火焰状态

  //数据打包
  sensor.AHT20_temperature = aht_data.temperature;
  sensor.AHT20_humidity = aht_data.humidity;
  sensor.BMP280_temperature = BMP280_temperature;
  sensor.BMP280_pressure = BMP280_pressure;
  sensor.light = voltage;
  sensor.current = hlw_data.current;
  sensor.power = hlw_data.power;
  sensor.energy = hlw_data.energy;
  sensor.voltage = hlw_data.voltage;
  sensor.nowstatus = nowstatus;
  sensor.timestamp = HAL_GetTick();
}

//有人自动开灯 在自动模式下开启
// 全局变量
static uint32_t lastDetectionTime = 0;
static bool alertActive = false;
static bool lastState = false; // 记录上一次检测的状态

void somebody_auto_light_TASK(void)
{

  if(driver_mode == AUTO_MODE) {
    bool currentState = IF_SOMBODY_STA; // 传感器状态
    uint32_t currentTime = HAL_GetTick();

    if (currentState) {
      // 检测到有人
      if (lastState == false) {
        // 状态由“无人”变为“有人”，才设置灯
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
        if(sensor.light<2.0){
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
        }
      }
      lastDetectionTime = currentTime; // 记录时间
      alertActive = true;
    } else {
      // 未检测到有人
      if (lastState == true) {
        // 状态由“有人”变为“无人”，可以不用立即关闭灯，等待超时
        // 但此处可以选择不变，或者确保在超时处理时关闭
      }
      if (alertActive && (currentTime - lastDetectionTime > 10000)) {
        // 超过30秒未检测到有人，要关闭灯
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
        alertActive = false;
      }
    }

    // 最后更新 lastState
    lastState = currentState;
  }
}

// 全局变量：存储上一次的状态
static bool lastFireState = false;

void fireSensor_TASK(void)
{
  bool currentFireState = !Fire_check; // 当前状态
  if (currentFireState != lastFireState) {
    // 状态变化
    if (currentFireState) {
      // 检测到火焰，蜂鸣器开
      Buzzer_StartBeep(BEEP_ERROR);
      WS2812_SetColorRGB(0, 255, 0, 0); // 红灯
      WS2812_Update();
    } else {
      // 火焰消失，蜂鸣器关
      Buzzer_StopBeep();
      WS2812_SetColorRGB(0, 0, 0, 0); // 红灯
      WS2812_Update();
    }
    lastFireState = currentFireState; // 更新状态
  }
}

static bool isNightOff = false;

void auto_control_TASK(void)
{
  if(driver_mode == AUTO_MODE) {
    RTC_TimeTypeDef sTime;
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);

    if(sTime.Hours == 12 && sTime.Minutes == 0 && sTime.Seconds == 0) {
      if(!isNightOff) {
        WS2812_SetColorRGB(0, 0, 0, 0); // 关闭灯
        WS2812_Update();
        isNightOff = true;
      }
    } else {
      // 其他时间可以重新开启控制或保持状态
      isNightOff = false;
    }
  }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  MX_ADC1_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
  //串口中断开启
  HAL_UARTEx_ReceiveToIdle_IT(&huart1, readBuffer, sizeof(readBuffer));

  // 执行内部校准
  HAL_ADCEx_Calibration_Start(&hadc1);

  //温湿度传感器初始化
  AHT20_Init();

  //气压传感器初始化
  bmp280_params_t  params;
  bmp280_init_default_params(&params);
  bmp280_dev.addr = BMP280_I2C_ADDRESS_0;
  bmp280_dev.i2c = &hi2c1;
  bmp280_init(&bmp280_dev, &params);

  //红外
  __HAL_TIM_ENABLE(&htim2);
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);

  //RGB灯
  WS2812_Init(&htim1);
//  WS2812_SetColorRGB(0, 255, 0, 0); // 设置第一个LED为红色
//  WS2812_Update(); // 更新显示


  //测试Flash
  //test_flash();

  //蜂鸣器初始化
  Buzzer_Init();

//  //开机提示音
  // Buzzer_StartBeep(BEEP_SHORT_BEEP);
  // for(int i=0;i<10;i++) {
  //   Buzzer_Update10ms();
  //   HAL_Delay(10);
  // }
  // Buzzer_StopBeep();

  //hlw8012
  HLW8012_Init(&htim3);

  //多任务处理
  my_taskOS_Init();
  my_taskOS_AddTask(analysisData_TASK,100); //解析串口数据
  my_taskOS_AddTask(read_sensor_TASK,200); //读取传感器
  my_taskOS_AddTask(buzzer_tick_TASK,10); //蜂鸣器tick
  my_taskOS_AddTask(get_hlw_data_TASK,500); //获取电能信息
  my_taskOS_AddTask(pack_data_TASK,200); //数据打包
  my_taskOS_AddTask(somebody_auto_light_TASK,100); //人
  my_taskOS_AddTask(fireSensor_TASK,100); //火焰
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1) {
    //调度任务
    my_taskOS_RunScheduler();
    HAL_Delay(10);
//    WS2812_RainbowEffect(50);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_ADC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1) {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
